﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace OxyPlot.CatExtension
{
    public static class Simd
    {
        public static (double, double) MinMax(Span<double> span)
        {
            if (Vector<double>.IsSupported && span.Length >= Vector<double>.Count * 2)
            {
                ref var start = ref MemoryMarshal.GetReference(span);
                var minVector = Vector.LoadUnsafe(ref start);
                var maxVector = Vector.LoadUnsafe(ref start);
                start = ref Unsafe.Add(ref start, Vector<double>.Count);

                for (int i = 1; i < span.Length / Vector<double>.Count; i++)
                {
                    var vector = Vector.LoadUnsafe(ref start);
                    minVector = Vector.Min(minVector, vector);
                    maxVector = Vector.Max(maxVector, vector);

                    start = ref Unsafe.Add(ref start, Vector<double>.Count);
                }

                var min = double.MaxValue;
                var max = double.MinValue;

                Span<double> buffer = stackalloc double[Vector<double>.Count];
                minVector.CopyTo(buffer);
                for (int i = 0; i < buffer.Length; i++)
                {
                    min = Math.Min(min, buffer[i]);
                }

                maxVector.CopyTo(buffer);
                for (int i = 0; i < buffer.Length; i++)
                {
                    max = Math.Max(max, buffer[i]);
                }

                for (int i = 0; i < span.Length % Vector<double>.Count; i++)
                {
                    var v = start;
                    if (v < min)
                    {
                        min = v;
                    }
                    if (v > max)
                    {
                        max = v;
                    }

                    start = ref Unsafe.Add(ref start, 1);
                }
                return (min, max);
            }
            else
            {
                var min = double.MaxValue;
                var max = double.MinValue;
                for (int i = 0; i < span.Length; i++)
                {
                    var v = span[i];
                    if (v < min)
                    {
                        min = v;
                    }
                    if (v > max)
                    {
                        max = v;
                    }
                }
                return (min, max);
            }
        }
    }
}
